home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-01-11 | 8.9 KB | 200 lines | [TEXT/CWIE] |
- /*———————————————————————————————————————————————————————————————————————————————————————————————————
- SPRITE PERSISTENCE README
- —————————————————————————
-
- • INTRO - WHAT IS IT
-
- This is a framework module for saving/reloading part or all of the data belonging:
- - to all the sprites in a spriteworld,
- - or to all the sprites in a given layer (that's the main objective of this thing),
- - or even to a single sprite (for special purposes I suppose).
- It works with DataPersistence for disk services.
- It's very small, 2K *including* DataPersistence (!), and as easy to use as we could
- make it.
- At this time, only the sprite positions are saved, since any other info would probably be very
- application-specific. Saving and reloading other sprite info is as easy as going into the
- SpritePersistence.c file, and adding more lines to SWGCopyFromSpriteToRecord and
- SWGCopyFromRecordToSprite (see the paragraph: COMPLETELY ADAPTABLE FOR ANY APPLICATION)
-
- Cool. Is it useful? Glad you asked.
-
-
- • HOW DID IT COME ABOUT ?
-
- This was initially intended to be added to Matthew's ButtonSprite, which we find
- very useful (matthewf@panix.com)
-
- ButtonSprite allows using sprites as buttons. It is very easy to set up and to use, and
- is structured in a way quite consistent with SW. (Good for you, Matthew)
-
- As an additional goodie, it allows moving the buttons around using the mouse. Perfect when
- you're tweaking your interface a lot. Much better than the usual shuttling between resedit,
- rebuilding your app, then rerunning it, and back again. BUT the new buttons' positions are
- forgotten when you quit.
-
- This is what SpritePersistence provides for. The main facility we wanted is saving/restoring
- the position of all sprites IN A GIVEN LAYER, into/from a resource file. As an extension, we
- provide for easily saving/loading ALL sprites in a spriteworld with a single function call;
- or you may, if you wish, save or reload a single sprite. These facilities might perhaps
- make this module useful in many situations.
-
- The actual file I/O is done by the DataPersistence module (see 'DataPersistence.note').
-
-
- • COMPLETELY ADAPTABLE FOR ANY APPLICATION
-
- The basic routines presented here simply save/restore the sprite's positions. This was the
- original goal for the module. But they also provide an easily modified framework for making
- persistent more of, or even all the data belonging to sprites, including the
- application-specific data which you probably associated to SpriteWorld's SpriteRec.
-
- You just have to :
-
- 1. modify the tSpriteSaveRec record declaration in the SpritePersistence.h header: include
- a declaration for each of the data fields you want to save;
-
- 2. add the necessary store/load intructions for your data fields, respectively in the
- SWGCopyFromSpriteToRecord and SWGCopyFromRecordToSprite routines. Take a look at how the
- sprite coordinates are loaded/stored to see how straightforward it is.
-
- That's all you need to do to adapt this module for saving/restoring your own data structures.
-
-
- • USAGE
-
- 1. To save, call:
-
- SWGSaveSpritesInLayer (yourLayerP); // a SpritePtr
- or
- SWGSaveSpritesInAllLayers (yourWorldP); // a SpriteWorldPtr
- or
- SWGSaveSingleSprite (layerNum, spriteNum, yourSpriteP); // SInt16, SInt16, SpritePtr
-
- 2. To load, call:
-
- SWGLoadSpritesInLayer (yourLayerP); // a SpritePtr
- or
- SWGLoadSpritesInAllLayers (yourWorldP); // a SpriteWorldPtr
- or
- SWGLoadSingleSprite (layerNum, spriteNum, yourSpriteP); // SInt16, SInt16, SpritePtr
-
- In the case of single sprites, for building the layerNum and spriteNum arguments, simply call:
-
- layerNum = SWGGetLayerNumber (yourLayerP);
- spriteNum = SWGGetSpriteNumber (yourSpriteP);
-
- or you may prefer:
-
- SWGSaveSingleSprite (SWGGetLayerNumber (yourLayerP),
- SWGGetSpriteNumber (yourSpriteP),
- yourSpriteP);
-
- SWGGetLayerNumber and SWGGetSpriteNumber do have a little overhead, but very little (for the first
- one, very _very_ little). They both simply follow the links from yourLayerP or yourSpriteP until the
- head of the list, counting the steps. They should be quite fast with the usual number of layers and
- sprites. Moreover they are only useful in conjunction with _single-sprite_ I/O; the layer and
- world I/O have no overhead at all.
-
- If you have many hundreds of sprites, SWGGetSpriteNumber would be proportionally slowed down,
- but you probably wouldn't use single sprite random I/O in the middle of an animation.
-
- If you _do_ have zillions of sprites, and need to save or load individual sprite data right in
- the middle of a tricky animation, you should simply precompute the sprite numbers and keep them.
- For instance store them in the sprite's userData field, or better, in your own sprite-related data
- record. After creating the sprites (and locking the world), call SWGGetSpriteNumber once for every
- sprite, and store the resulting numbers. This will only cost 2 bytes per sprite, i.e. 1K if you
- use 500 sprites (I don't know of anyone who uses that many).
-
-
- • FILE MANAGEMENT
-
- File usage is transparent, SpritePersistence opens and closes the file when needed.
-
- For more details, see 'DataPersistence.note'.
-
-
- • EXCEPTIONS, SPECIAL CASES
-
- When one of the SWGLoadSpritesXXX routines does not find the expected resources, it does
- nothing: the sprites will be left in their original state. There's a good reason for
- this: if your program starts by loading sprite data, it will work even the first time,
- when the file is empty.
-
- You still have, of course, in your app, to initialize the sprites to default parameters,
- since these will be used as default values the very first time, or when you have trashed
- the save file.
-
-
- • FAQ
-
- ----- 1 -----
-
- Q: Don't I need to open/close the external save file? I notice you didn't.
-
- A: No, you don't need to. This is handled automatically by SpritePersistence. By default,
- the external save file behaves, from your point of view, as a (physically separate) extension
- of your own resource fork.
-
- You just use the calls described above as if the file didn't exist. It will be opened
- automatically, and closed before returning. Don't worry about it, it's simple and efficient;
- and as a bonus, data safety is about as good as it can reasonably get, since the written
- data gets flushed to disk when the file is closed.
-
- If however you prefer to do the open/close yourself, just do it. SpritePersistence will notice
- that you did, and won't interfere with you: won't try to reopen it, and won't close it when done.
- e.g.:
- err = SWGOpenSpriteSaveFile ();
-
- // ... your processing ...
-
- SWGSaveSingleSprite (layerNum, spriteNum, yourSpriteP); // any number of times
-
- // ... your processing ...
-
- SWGLoadSingleSprite (layerNum, spriteNum, yourSpriteP); // any number of times
-
- // ... your processing ...
-
- SWGCloseSpriteSaveFile ();
-
- This may be advisable if you wish to do single-sprite access; in that case, the
- automatic file open and close wouldn't be efficient. Even so, if the accesses are not
- very frequent, or not in the middle of a tricky animation, you may prefer to use the
- automatic open feature, in most cases there won't be a noticeable performance hit.
-
- ----- 2 -----
-
- Q: Why the layerNum and spriteNum arguments in SWGSave/LoadSingleSprite?
- A: Because they are used, with to kMaxSpritesInOneLayer, to compute the resource ID for
- each sprite:
- id = layerNum * kMaxSpritesInOneLayer + spriteNum.
- Think of the layerNum as a vertical coord, the spriteNum as a horizontal coord,
- kMaxSpritesInOneLayer as rowBytes, and the resulting ID as a screen address...
-
- There is no drawback to having a big kMaxSpritesInOneLayer, except you must keep the value
- layerNum * kMaxSpritesInOneLayer * spriteNum inside the acceptable values for a resource
- ID (< 2^15). For most purposes, 100 <= kMaxSpritesInOneLayer <= 200 is probably ok.
- But if you think you may have e.g. 369 sprites (if all your sprites explode at once :), just
- put in 400. Even if you have 10 layers, the highest record number would then be 4369.
-
- ----- 3 -----
-
- Q: Why use the resource format?
- A: Why resources at all? Because they are convenient, and there are utilities for doing
- various things with resources. It's widely known that resource read/write *may* be less
- efficient than custom data formats, but that's only a concern for a high number of items,
- say many thousands. That's not what this module is aimed at.
-
- However, if this module is _ever_ used heavily enough to discover cases where performance
- becomes an issue, it would be fairly easy to modify the two routines which do actual
- file access, and manage a custom data format (if you want to do it yourself, please
- send me the source :).
-
-
- • TO DO
-
- - TilePersistence: the same service for tiles that SpritePersistence provides for sprites.
-
- ———————————————————————————————————————————————————————————————————————————————————————————————————*/
- // feedback: macdev@tnuctip.com
-